package com.quwan.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.quwan.app.service.DispatchOrderService;
import com.quwan.app.service.MemberService;
import com.quwan.app.service.PrePaymentInterface;
import com.quwan.app.service.ProductCategoryService;
import com.quwan.app.vo.PushOfflineMsgParams;
import com.quwan.app.vo.dispatch.*;
import com.quwan.app.vo.pay.BalancePrePayment;
import com.quwan.app.vo.pay.PrePayParams;
import com.quwan.app.vo.pay.PrePayment;
import com.quwan.app.vo.pay.WxPrePayment;
import com.quwan.common.BaseService;
import com.quwan.common.Check;
import com.quwan.common.enums.*;
import com.quwan.common.exception.ExpCode;
import com.quwan.common.query.LambdaQueryWrapperX;
import com.quwan.common.result.PageResult;
import com.quwan.component.AsyncTaskComponent;
import com.quwan.config.yml.OssConfig;
import com.quwan.config.yml.PaymentBalanceConfig;
import com.quwan.constans.AppConst;
import com.quwan.constans.CacheKey;
import com.quwan.entity.*;
import com.quwan.mapper.*;
import com.quwan.utils.DateUtils;
import com.quwan.utils.Parse;
import com.quwan.utils.PayUtil;
import com.quwan.utils.redis.Redis;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author quan
 * @date 2022-05-25 10:03
 */
@Service
@RequiredArgsConstructor
public class DispatchOrderServiceImpl extends BaseService implements DispatchOrderService {
    @Value("${spring.profiles.active}")
    private String env;
    @Value("${member.head}")
    private String headImg;
    @Value("${msg.dispatch.apply}")
    private String applyMsg;

    private final TProductCategoryMapper categoryMapper;
    private final ProductCategoryService categoryService;
    private final TDispatchOrderMapper dispatchOrderMapper;
    private final TMemberMapper memberMapper;
    private final TDispatchOrderApplyMapper applyMapper;
    private final OssConfig ossConfig;
    private final TMemberBalanceLogMapper balanceLogMapper;
    private final PaymentBalanceConfig balanceConfig;
    private final TSpreadSettingMapper spreadSettingMapper;
    private final TOrderSplitMapper splitMapper;
    private final MemberService memberService;
    private final Redis redis;
    private final TScaleSettingMapper scaleSettingMapper;
    private final AsyncTaskComponent taskComponent;

    @Override
    public PrePayment PrePayDispatchOrder(String mId, DispatchOrderParams params, PrePaymentInterface payInstance) {
        TProductCategory category = null;
        if (params.getCategoryId() != null)
            category = categoryService.getProductCategoryById(params.getCategoryId());
        category = Optional.ofNullable(category).orElse(new TProductCategory().setId(0L).setCaption("派单帮忙"));

        //生成支付订单id
        Long orderId = IdWorker.getId();

        PaymentEnum paymentEnum = PaymentEnum.getByType(params.getPayType());
        Check.notNull(paymentEnum, ExpCode.PAY_NOT_SUPPORT);

        TScaleSetting setting = scaleSettingMapper.selectOne(new QueryWrapper<>(new TScaleSetting().setType(OrderScaleEnum.DISPATCH_ORDER_BEFORE.getType())));
        BigDecimal scale = new BigDecimal(OrderScaleEnum.DISPATCH_ORDER_BEFORE.getDefScale());
        if (setting != null && setting.getScale().doubleValue() > 0)
            scale = setting.getScale();
        //派单定金 尾款价格计算
        BigDecimal price = new BigDecimal(params.getPrice());
        BigDecimal beforePrice = price.multiply(scale);
        BigDecimal afterPrice = price.subtract(beforePrice);


        //预支付参数
        PrePayParams prePayParams = new PrePayParams(
                params.getPayType().equals(PaymentEnum.SYSTEM_PAY.getType()) ? beforePrice.stripTrailingZeros().toPlainString() : PayUtil.getPayAmountByEnv(env, beforePrice),
                orderId.toString(),
                "派单定金支付",
                paymentEnum.getDispatchBefore(),
                mId);
        //发起预支付
        PrePayment prePayment = payInstance.prePayment(prePayParams);
        TDispatchOrder order = new TDispatchOrder()
                .setOrderId(orderId)
                .setCategory(category.getCaption())
                .setCategoryId(category.getId())
                .setContent(params.getContent())
                .setBeginTime(DateUtils.localDateTimeOfStr(params.getBeginTime()))
                .setStatus(-1)
                .setOrderTime(params.getOrderTime())
                .setBeforePrice(beforePrice)
                .setAfterPrice(afterPrice)
                .setImgs(params.getImgs())
                .setAddress(params.getAddress())
                .setPrice(new BigDecimal(params.getPrice()))
                .setCityCode(params.getCityCode())
                .setCityName(params.getCityName())
                .setMId(Parse.toLong(mId))

                .setBeforePayMethod(Parse.toInt(params.getPayType()))
                .setUnit(params.getUnit());

        Check.state(dispatchOrderMapper.insert(order) == 1, ExpCode.DB_UPDATE_ERR);
        return prePayment.setId(orderId.toString());
    }

    @Override
    public PageResult<DispatchOrderDTO> getDispatchOrderList(int pageNo, int pageSize, String cityCode, String categoryId, String sortPrice) {
        LambdaQueryWrapperX<TDispatchOrder> where = new LambdaQueryWrapperX<TDispatchOrder>()
                // .eqIfPresent(TDispatchOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                .eqIfPresent(TDispatchOrder::getStatus, DispatchOrderStatusEnum.await.getStatus())
                .eqIfPresent(TDispatchOrder::getCityCode, StringUtils.isBlank(cityCode) ? null : cityCode)
                .eqIfPresent(TDispatchOrder::getCategoryId, StringUtils.isBlank(categoryId) ? null : categoryId);
        if (StringUtils.isNotBlank(sortPrice)) {
            if (sortPrice.equals("1"))
                where.orderByDesc(TDispatchOrder::getPrice);
            where.orderByAsc(TDispatchOrder::getPrice);
        } else where.orderByDesc(TDispatchOrder::getOrderNum, TDispatchOrder::getAddTime);

        //查询派单数据
        Page<TDispatchOrder> res = dispatchOrderMapper.selectPage(new Page<>(pageNo, pageSize), where);

        if (res.getRecords().isEmpty())
            return new PageResult<>();
        //派单用户集合
        List<Long> mIds = res.getRecords().stream().map(TDispatchOrder::getMId).distinct().collect(Collectors.toList());
        Map<Long, TMember> memberMap = memberMapper
                .selectList(
                        new LambdaQueryWrapper<TMember>()
                                .select(TMember::getId, TMember::getNickName, TMember::getImgUrl, TMember::getIdStatus, TMember::getFaceStatus,
                                        TMember::getArea, TMember::getLastVisitTime)
                                .in(TMember::getId, mIds)
                )
                .stream()
                .collect(Collectors.toMap(TMember::getId, v -> v));
        String ids = res.getRecords().stream().map(TDispatchOrder::getId).map(String::valueOf).collect(Collectors.joining(","));
        List<ApplyCountDTO> count = applyMapper.selectCountByIds(ids);
        ImmutableMap<Long, ApplyCountDTO> countMap = Maps.uniqueIndex(count, ApplyCountDTO::getOrderId);


        //封装响应参数
        List<DispatchOrderDTO> ret = res
                .getRecords()
                .stream()
                .map(dispatchOrder ->
                        {
                            TMember member = Optional.ofNullable(memberMap.get(dispatchOrder.getMId())).orElse(new TMember());
                            return new DispatchOrderDTO()
                                    .setMId(dispatchOrder.getMId().toString())
                                    .setArea(dispatchOrder.getCityName())
                                    .setContent(dispatchOrder.getContent())
                                    .setCategory(dispatchOrder.getCategory())
                                    .setId(dispatchOrder.getId().toString())
                                    .setPrice(dispatchOrder.getPrice().stripTrailingZeros().toPlainString())
                                    .setFaceAuth(member.getFaceStatus() > 0)
                                    .setRealNameAuth(member.getIdStatus() > 0)
                                    .setOnline(DateUtils.computeOnlineTime(member.getLastVisitTime()))
                                    .setNickname(member.getNickName())
                                    .setVisitCount(redis.hIncrBy(CacheKey.DISPATCH.visitCount, dispatchOrder.getId().toString(), 0))
                                    .setMemberImg(Optional.ofNullable(member.getImgUrl()).map(m -> ossConfig.getHostname() + "/" + m).orElse(""))
                                    .setApplyCount(Optional.ofNullable(countMap.get(dispatchOrder.getId())).orElse(new ApplyCountDTO()).getCount());//DONE 申请人数
                        }

                )
                .collect(Collectors.toList());

        return new PageResult<DispatchOrderDTO>()
                .setPages(res.getPages())
                .setTotal(res.getTotal())
                .setCurrent(res.getCurrent())
                .setSize(res.getSize())
                .setRecords(ret);
    }

    @Override
    public DispatchOrderDTO getDispatchOrderDetail(String mId, String dispatchOrderId) {
        //派单数据查询
        TDispatchOrder order = dispatchOrderMapper.selectOne(new LambdaQueryWrapper<TDispatchOrder>().eq(TDispatchOrder::getId, dispatchOrderId)
                .eq(TDispatchOrder::getStatus, DispatchOrderStatusEnum.await.getStatus()));
        Check.notNull(order, ExpCode.ORDER_NOT_EXIST);

        //派单用户信息
        TMember member = memberMapper.selectOne(new LambdaQueryWrapper<TMember>()
                .select(TMember::getNickName, TMember::getImgUrl, TMember::getIdStatus, TMember::getFaceStatus)
                .eq(TMember::getId, order.getMId()));
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);

        //用户时间要求数据处理

       /* List<SelectorWeekVo> weekVos = strToList(",", order.getTimeLimit())
                .stream()
                .filter(f -> Pattern.matches(AppConst.PUBLISH_ORDER_TIME, f))
                .map(m -> {
                    String[] split = m.split("_");
                    String[] timeSplit = split[1].split("-");
                    String week = split[0];
                    String beginTime = timeSplit[0];
                    String endTime = timeSplit[1];

                    LocalTime begin = DateUtils.localTimeOfStr(beginTime);
                    LocalTime end = DateUtils.localTimeOfStr(endTime);

                    Long max = begin.isBefore(end) ? Duration.between(begin, end).toHours() : 0;
                    String realData = DateUtils.week_DateMap().get(week);

                    LocalDateTime realLocalDateTime = LocalDateTime.of(DateUtils.localDateOfStr(realData), begin);

                    return new SelectorWeekVo()
                            .setTips(WeekTips.getStr(Integer.parseInt(week)))
                            .setTime(beginTime)
                            .setWeek(LocalDate.now().isEqual(realLocalDateTime.toLocalDate()) ? "今天" : realLocalDateTime.format(DateTimeFormatter.ofPattern("MM-dd")))
                            .setMax(max)
                            //.setWeek(week)
                            .setRealDate(DateUtils.getLocalDateTimeStr(realLocalDateTime))
                            .setSimpleDate(realLocalDateTime.format(DateTimeFormatter.ofPattern("MM-dd")))
                            .setStatus(CommonStatus.NORMAL.getType());
                })
                .sorted(Comparator.comparing(SelectorWeekVo::getRealDate))
                .collect(Collectors.toList());
*/

        return new DispatchOrderDetailDTO()
                //  .setSelector(weekVos)
                .setApplyBtn(
                        applyMapper
                                .selectCount(
                                        new QueryWrapper<>(
                                                new TDispatchOrderApply()
                                                        .setUnLock(dispatchOrderId + mId)
                                                        .setType(ApplyTypeEnum.DISPATCH_ORDER.getType())
                                                        .setStatus(DispatchOrderStatusEnum.await.getStatus())))
                                == 0
                )
                .setImgs(strToList(",", order.getImgs()).stream().filter(StringUtils::isNotBlank).map(url -> ossConfig.getHostname() + "/" + url).distinct().collect(Collectors.toList()))
                .setVisitCount(redis.hIncrBy(CacheKey.DISPATCH.visitCount, dispatchOrderId, 1))
                .setMId(order.getMId().toString())
                .setArea(order.getCityName())
                .setContent(order.getContent())
                .setCategory(order.getCategory())
                .setId(order.getId().toString())
                .setPrice(order.getPrice().stripTrailingZeros().toPlainString())
                .setFaceAuth(member.getFaceStatus() > 0)
                .setRealNameAuth(member.getIdStatus() > 0)
                .setNickname(member.getNickName())
                .setBeginTime(order.getBeginTime())
                .setOrderTime(order.getOrderTime())
                .setAddress(order.getAddress())
                .setMemberImg(Optional.ofNullable(member.getImgUrl()).map(m -> ossConfig.getHostname() + "/" + m).orElse(""))
                .setApplyCount(
                        applyMapper
                                .selectCount(
                                        new QueryWrapper<>(
                                                new TDispatchOrderApply()
                                                        .setOrderId(Parse.toLong(dispatchOrderId))
                                                        .setType(ApplyTypeEnum.DISPATCH_ORDER.getType())
                                                        .setStatus(DispatchOrderStatusEnum.await.getStatus())))
                );//DONE 申请人数

    }

    @Override
    public Boolean applyDispatchOrder(String mId, String id, String date, String time) {
//        String[] dateStr = date.split("-");
//        String month = dateStr[0];
//        String dayOfMonth = dateStr[1];
//        LocalDateTime applyTime = LocalDateTime.of(LocalDate.of(LocalDate.now().getYear(), Parse.toInt(month), Parse.toInt(dayOfMonth)), LocalTime.parse(time));
        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getImgUrl)
                        .eq(TMember::getId, mId)
                        .eq(TMember::getStatus, CommonStatus.NORMAL.getType())
        );
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        Integer integer = applyMapper.saveApplyInfo(
                new TDispatchOrderApply()
                        .setApplyTime(LocalDateTime.now())
                        .setOrderId(Parse.toLong(id))
                        .setApplyMId(Parse.toLong(mId))
                        .setType(ApplyTypeEnum.DISPATCH_ORDER.getType())
                        .setStatus(DispatchOrderStatusEnum.await.getStatus())
                        .setMemberImg(StringUtils.isBlank(member.getImgUrl()) ? headImg : member.getImgUrl())
                        .setAddTime(LocalDateTime.now())
                        .setUnLock(id + mId));
        TDispatchOrder order = dispatchOrderMapper.selectById(id);
        Check.notNull(order, ExpCode.ORDER_NOT_EXIST);
        PushOfflineMsgParams offlineMsgParams = pushOffLineMsg(order.getMId(), null, id, applyMsg, applyMsg, AppConst.OFFLINE_MSG_DISPATCH_ORDER_ORDER_APPLY);
        taskComponent.pushOfflineMsgToMember(offlineMsgParams);

        return integer > 0;
    }

    @Override
    public String checkApply(String mId, String id) {
        TDispatchOrder order = dispatchOrderMapper
                .selectOne(
                        new QueryWrapper<>(
                                new TDispatchOrder()
                                        .setId(Parse.toLong(id))
                        )
                );
        Check.notNull(order, ExpCode.ORDER_NOT_EXIST);


        if (order.getStatus() != 0)
            return "用户已选中接单人,申请别的订单试试~~";
        else if (order.getMId().toString().equals(mId))
            return "不可以申请自己订单哦~";
      /*  else if (
                applyMapper.selectCount(new QueryWrapper<>(new TDispatchOrderApply().setUnLock(id + mId).setStatus(DispatchOrderStatusEnum.await.getStatus()))) > 0)
            return "您已申请接单,请勿重复申请~~";*/
        else {
            List<TDispatchOrderApply> applies = applyMapper.selectList(new QueryWrapper<>(new TDispatchOrderApply().setOrderId(Parse.toLong(id)).setStatus(DispatchOrderStatusEnum.await.getStatus())));
            if (applies.size() > 5)
                return "当前申请人数已达上限";
            long count = applies.stream().filter(filter -> filter.getApplyMId().equals(Parse.toLong(mId))).count();
            if (count != 0)
                return "您已申请接单,请勿重复申请~~";
            return null;
        }

    }

    @Override
    public PageResult<ConsumerDispatchOrderDTO> consumerDispatchOrderList(String id, Integer type, int pageNo, int pageSize) {
        Page<TDispatchOrder> res = dispatchOrderMapper
                .selectPage(
                        new Page<>(pageNo, pageSize),
                        new LambdaQueryWrapper<TDispatchOrder>()
                                .select(TDispatchOrder::getId, TDispatchOrder::getStatus, TDispatchOrder::getContent, TDispatchOrder::getPrice, TDispatchOrder::getCategory, TDispatchOrder::getAddTime, TDispatchOrder::getImgs)
                                .eq(TDispatchOrder::getMId, id)
                                .eq(type != -1, TDispatchOrder::getStatus, type)
                                //.eq(TDispatchOrder::getPayStatus, PayStatusEnum.FINISH.getType())
                                .orderByDesc(TDispatchOrder::getAddTime)
                );

        if (res.getRecords().isEmpty())
            return new PageResult<>();

        String ids = res.getRecords().stream().map(TDispatchOrder::getId).map(String::valueOf).collect(Collectors.joining(","));


        Map<Long, List<TDispatchOrderApply>> applyMemberImgs = type == 0 ? applyMapper.selectApplyMemberImg(ids)
                .stream()
                .collect(Collectors.groupingBy(TDispatchOrderApply::getOrderId)) :
                Maps.newHashMap();

        List<ConsumerDispatchOrderDTO> ret = res
                .getRecords()
                .stream()
                .map(m ->
                        new ConsumerDispatchOrderDTO()
                                .setCategory(m.getCategory())
                                .setId(m.getId().toString())
                                .setContent(m.getContent())
                                .setStatus(m.getStatus())
                                .setPrice(m.getPrice().stripTrailingZeros().toPlainString())
                                .setApplyMember(
                                        Optional
                                                .ofNullable(applyMemberImgs.get(m.getId()))
                                                .orElse(Lists.newArrayList())
                                                .stream()
                                                .map(info -> new ApplyMemberInfo().setMemberImg(ossConfig.getHostname() + "/" + (StringUtils.isBlank(info.getMemberImg()) ? headImg : info.getMemberImg())).setMId(info.getApplyMId().toString()))
                                                .collect(Collectors.toList())
                                )
                                .setImgs(strToList(",", m.getImgs()).stream().filter(StringUtils::isNotBlank).map(url -> ossConfig.getHostname() + "/" + url).collect(Collectors.toList()))
                                .setDate(DateUtils.getLocalDateTimeStr(m.getAddTime(), DateUtils.YYYY_MM_DD))
                )
                .collect(Collectors.toList());


        return new PageResult<ConsumerDispatchOrderDTO>()
                .setRecords(ret)
                .setSize(res.getSize())
                .setCurrent(res.getCurrent())
                .setTotal(res.getTotal())
                .setPages(res.getPages());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public PrePayment chooseServiceMember(String mId, String id, String applyId, PrePaymentInterface payInstance, String payType) {
        TDispatchOrderApply applyOrder = applyMapper.selectById(applyId);
        TDispatchOrder dispatchOrder = dispatchOrderMapper.selectOne(
                new LambdaQueryWrapper<TDispatchOrder>()
                        .eq(TDispatchOrder::getId, id)
                        .eq(TDispatchOrder::getMId, mId)
        );
        Check.state(applyOrder != null && dispatchOrder != null, ExpCode.ORDER_INFO_ERR);


        Check.state(PayStatusEnum.NOT.getType().equals(dispatchOrder.getPayStatus()) &&
                DispatchOrderStatusEnum.await.getStatus().equals(dispatchOrder.getStatus()), ExpCode.ORDER_STATUS_EXP);

        Check.state(applyOrder.getOrderId().equals(dispatchOrder.getId()), ExpCode.APPLY_MEMBER_EXP);

        //发起预支付请求

        PaymentEnum paymentEnum = PaymentEnum.getByType(payType);
        Check.notNull(paymentEnum, ExpCode.PAY_NOT_SUPPORT);

        //预支付参数
        PrePayParams prePayParams = new PrePayParams(
                payType.equals(PaymentEnum.SYSTEM_PAY.getType()) ? dispatchOrder.getAfterPrice().toString() : PayUtil.getPayAmountByEnv(env, dispatchOrder.getAfterPrice()),
                dispatchOrder.getId().toString(),
                "派单尾款支付",
                paymentEnum.getDispatch(),
                mId);
        //发起预支付
        PrePayment prePayment = payInstance.prePayment(prePayParams);


        //派单数据添加
        String prePayId = "";
        //判断支付类型  设置预支付流水
        if (prePayment instanceof WxPrePayment)
            prePayId = ((WxPrePayment) prePayment).getPrePayId();
        else if (prePayment instanceof BalancePrePayment)
            prePayId = ((BalancePrePayment) prePayment).getPreId();

        //更新订单信息

        LocalDateTime beginTime = applyOrder.getApplyTime();
        Long serviceMember = applyOrder.getApplyMId();

        int row = dispatchOrderMapper.update(
                null,
                new LambdaUpdateWrapper<TDispatchOrder>()
                        .set(TDispatchOrder::getServiceId, serviceMember)
                        //.set(TDispatchOrder::getStatus, DispatchOrderStatusEnum.processing.getStatus())
                        .set(TDispatchOrder::getConfirmTime, LocalDateTime.now())
                        .set(TDispatchOrder::getPayMethod, payType)
                        //  .set(TDispatchOrder::getBeginTime, beginTime)
                        .set(TDispatchOrder::getPrePayId, prePayId)
                        //  .set(TDispatchOrder::getVisitCount, redis.hIncrBy(CacheKey.DISPATCH.visitCount, id, 0))
                        .eq(TDispatchOrder::getId, dispatchOrder.getId())
        );
        Check.state(row == 1, ExpCode.DB_UPDATE_ERR);


        return prePayment.setId(dispatchOrder.getId().toString());

    }

    @Override
    public PageResult<ApplyMemberDTO> getChooseServiceList(String id, int pageNo, int pageSize) {
        Page<ApplyMemberDTO> res = applyMapper.selectPageByOrderId(new Page<>(pageNo, pageSize), id);
        return new PageResult<ApplyMemberDTO>()
                .setPages(res.getPages())
                .setRecords(res.getRecords().stream().map(m -> m.setMemberImg(StringUtils.isBlank(m.getMemberImg()) ? "" : ossConfig.getHostname() + "/" + m.getMemberImg())).collect(Collectors.toList()))
                .setTotal(res.getTotal())
                .setSize(res.getSize())
                .setCurrent(res.getCurrent());

    }

    @Override
    public ConsumeOrderDetailInfoDTO orderStatusInfo(String mId, String id) {

        ConsumeOrderDetailInfoDTO ret = new ConsumeOrderDetailInfoDTO();
        //派单信息
        TDispatchOrder dispatchOrder = dispatchOrderMapper.selectById(id);
        Check.notNull(dispatchOrder, ExpCode.ORDER_NOT_EXIST);

        String dispatchMember = Optional.ofNullable(dispatchOrder.getMId()).map(String::valueOf).orElse("");
        String serviceMember = Optional.ofNullable(dispatchOrder.getServiceId()).map(String::valueOf).orElse("");

        if (!mId.equals(dispatchMember) && !mId.equals(serviceMember))
            return ret;


        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getNickName, TMember::getImgUrl, TMember::getArea, TMember::getId)
                        .eq(TMember::getId, mId.equals(dispatchMember) ? serviceMember : dispatchMember)
        );

        // Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        member = Optional.ofNullable(member).orElse(new TMember());
        return ret
                .setDispatchOrderId(dispatchOrder.getId().toString())
                .setContent(dispatchOrder.getContent())
                .setPrice(dispatchOrder.getPrice().stripTrailingZeros().toPlainString())
                .setBeginDate(dispatchOrder.getBeginTime().toLocalDate())
                .setBeginTime(dispatchOrder.getBeginTime().toLocalTime())
                .setOrderId(dispatchOrder.getOrderId().toString())
                .setOrderTime(dispatchOrder.getAddTime())
                .setMId(member.getId().toString())
                .setNickname(member.getNickName())
                .setStatus(dispatchOrder.getStatus())
                .setDuration(dispatchOrder.getOrderTime())
                .setMemberImg(StringUtils.isBlank(member.getImgUrl()) ? "" : ossConfig.getHostname() + "/" + member.getImgUrl())
                .setArea(mId.equals(serviceMember) ? dispatchOrder.getCityName() : parseArea(member.getArea()))
                /*    .setCancel(
                            mId.equals(serviceMember) ?
                                    LocalDateTime.now().isBefore(dispatchOrder.getBeginTime())
                                    : mId.equalsIgnoreCase(dispatchMember)
                                    && DispatchOrderStatusEnum.processing.getStatus().equals(dispatchOrder.getStatus())
                                    && LocalDateTime.now().isBefore(dispatchOrder.getBeginTime())


                    )*/
                .setCancel(DispatchOrderStatusEnum.await.getStatus().equals(dispatchOrder.getStatus()))
                .setFinished(mId.equalsIgnoreCase(dispatchMember)
                        && LocalDateTime.now().isAfter(dispatchOrder.getBeginTime())
                        && DispatchOrderStatusEnum.processing.getStatus().equals(dispatchOrder.getStatus()));


    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public Boolean cancelOrder(String mId, String id) {
        TDispatchOrder dispatchOrder = dispatchOrderMapper.selectById(id);
        Check.notNull(dispatchOrder, ExpCode.ORDER_NOT_EXIST);

        String dispatchMember = Optional.ofNullable(dispatchOrder.getMId()).map(String::valueOf).orElse("");
        String serviceMember = Optional.ofNullable(dispatchOrder.getServiceId()).map(String::valueOf).orElse("");

        Check.state(mId.equals(dispatchMember) || mId.equals(serviceMember), ExpCode.OPERATE_FAIL);
        Check.state(DispatchOrderStatusEnum.await.getStatus().equals(dispatchOrder.getStatus()) &&
                PayStatusEnum.FINISH.getType().equals(dispatchOrder.getBeforeStatus()), ExpCode.ORDER_STATUS_NOT_SPORT_CANCEL);

      /*  if (mId.equals(serviceMember)) {
            //接单人取消

            //恢复派单订单状态
            int orderRow = dispatchOrderMapper
                    .update(null,
                            new LambdaUpdateWrapper<TDispatchOrder>()
                                    .set(TDispatchOrder::getServiceId, null)
                                    .set(TDispatchOrder::getStatus, DispatchOrderStatusEnum.await.getStatus())
                                    .set(TDispatchOrder::getBeginTime, null)
                                    .eq(TDispatchOrder::getId, dispatchOrder.getId())

                    );
            if (orderRow == 1)
                //恢复申请接单列表
                applyMapper.update(
                        null,
                        new LambdaUpdateWrapper<TDispatchOrderApply>()
                                .set(TDispatchOrderApply::getStatus, CommonStatus.NORMAL.getType())
                                .eq(TDispatchOrderApply::getOrderId, dispatchOrder.getId())
                                .ne(TDispatchOrderApply::getApplyMId, serviceMember));

            else
                return false;

        } else {*/
        //派单人取消订单  金额退回余额
        TMember member = memberMapper.selectOne(new QueryWrapper<>(new TMember().setId(dispatchOrder.getMId())));
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        BigDecimal price = dispatchOrder.getBeforePrice();
        BigDecimal balance = member.getBalance();
        BigDecimal scale = BigDecimal.ZERO;
        BigDecimal fee = BigDecimal.ZERO;
        if (dispatchOrder.getMId().toString().equals(dispatchMember)) {
            TScaleSetting tScaleSetting = scaleSettingMapper.selectOne(new QueryWrapper<>(new TScaleSetting().setType(OrderScaleEnum.DISPATCH_ORDER_CANCEL.getType())));
            scale = Optional.ofNullable(tScaleSetting).map(TScaleSetting::getScale).orElse(new BigDecimal(OrderScaleEnum.DISPATCH_ORDER_CANCEL.getDefScale()));
            fee = price.multiply(scale).setScale(2, 5);
            price = price.subtract(fee);
        }

        int memberRow = memberMapper.update(null,
                new LambdaUpdateWrapper<TMember>()
                        .set(TMember::getBalance, balance.add(price))
                        .set(TMember::getVersion, member.getVersion() + 1)
                        .eq(TMember::getAutoId, member.getAutoId())
                        .eq(TMember::getVersion, member.getVersion())

        );

        int orderRow = dispatchOrderMapper.update(null,
                new LambdaUpdateWrapper<TDispatchOrder>()
                        .set(TDispatchOrder::getStatus, DispatchOrderStatusEnum.cancel.getStatus())
                        .set(TDispatchOrder::getAudit, 1)
                        .eq(TDispatchOrder::getId, dispatchOrder.getId())
        );
        applyMapper.update(null,
                new LambdaUpdateWrapper<TDispatchOrderApply>()
                        .set(TDispatchOrderApply::getStatus, DispatchOrderStatusEnum.del.getStatus())
                        .eq(TDispatchOrderApply::getOrderId, dispatchOrder.getId()));
        int logRow = balanceLogMapper.insert(
                new TMemberBalanceLog()
                        .setMId(member.getId())
                        .setTips(BalanceLogEnum.DISPATCH_CANCEL.getTips())
                        .setTradeType(BalanceLogEnum.DISPATCH_CANCEL.getType())
                        .setStatus(PayStatusEnum.FINISH.getType())
                        .setPrePayId(dispatchOrder.getPrePayId())
                        .setBalance(balance.add(price))
                        .setMoney(price)
                        .setBeforeM(balance)
                        .setFeeScale(scale.stripTrailingZeros().toPlainString())
                        .setFee(fee)
                        .setMethod(dispatchOrder.getPayMethod())
                        .setTradeNo(dispatchOrder.getOrderId().toString())
                        .setPayTime(LocalDateTime.now())
                        .setTransactionId(dispatchOrder.getTransactionId() + "")
        );
        Check.state(memberRow == 1 && orderRow == 1 && logRow == 1, ExpCode.DB_UPDATE_ERR);
        //}

        return true;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public Boolean confirmOrder(String mId, String id) {
        //发单信息
        TDispatchOrder order =
                dispatchOrderMapper
                        .selectOne(
                                new LambdaQueryWrapper<TDispatchOrder>()
                                        .eq(TDispatchOrder::getId, id)
                                        .eq(TDispatchOrder::getMId, mId)
                                        .eq(TDispatchOrder::getStatus, DispatchOrderStatusEnum.processing.getStatus())
                        );
        Check.notNull(order, ExpCode.ORDER_INFO_ERR);
        //接单用户
        Long serviceId = order.getServiceId();
        BigDecimal price = order.getPrice();

        //接单人信息
        TMember serviceMember = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getId, TMember::getVersion, TMember::getBalance, TMember::getIncomeMoney, TMember::getParentId)
                        .eq(TMember::getId, serviceId)
        );

//        //派单抽成比例
//        BigDecimal dispatchScale = new BigDecimal(balanceConfig.getDispatchScale());
//        //接单人利润
//        BigDecimal memberProfit = price.subtract(price.multiply(dispatchScale));
//        //公司利润 如果存在推广 推广利润 从 公司利润扣减
//        BigDecimal companyProfit = price.subtract(memberProfit);
//        //推广利润
//        BigDecimal spreadProfit = BigDecimal.ZERO;
//        //推广比例
//        BigDecimal scale = BigDecimal.ZERO;
        TScaleSetting setting = scaleSettingMapper.selectOne(new QueryWrapper<>(new TScaleSetting().setType(OrderScaleEnum.DISPATCH_ORDER_AFTER.getType())));

        BigDecimal scale = new BigDecimal(OrderScaleEnum.DISPATCH_ORDER_BEFORE.getDefScale());
        if (setting != null && setting.getScale().doubleValue() > 0)
            scale = setting.getScale();
        BigDecimal companyProfit = price.multiply(scale);

        BigDecimal memberProfit = price.subtract(companyProfit);


        //接单人金额添加
        BigDecimal serviceBalance = serviceMember.getBalance().add(memberProfit);
        int row = memberMapper
                .update(null,
                        new LambdaUpdateWrapper<TMember>()
                                .set(TMember::getBalance, serviceBalance)
                                .set(TMember::getIncomeMoney, serviceMember.getIncomeMoney().add(memberProfit))
                                .set(TMember::getVersion, serviceMember.getVersion() + 1)
                                .eq(TMember::getId, serviceMember.getId())
                                .eq(TMember::getVersion, serviceMember.getVersion())
                );


        //接单人金额日志记录
        int logRow = balanceLogMapper.insert(
                new TMemberBalanceLog()
                        .setStatus(CommonStatus.NORMAL.getType())
                        .setMId(serviceMember.getId())
                        .setPayTime(LocalDateTime.now())
                        .setTips(BalanceLogEnum.DISPATCH_FINISH.getTips())
                        .setTradeType(BalanceLogEnum.DISPATCH_FINISH.getType())
                        .setMethod(Integer.parseInt(PaymentEnum.SYSTEM_PAY.getType()))
                        .setTradeNo(order.getOrderId().toString())
                        .setTransactionId(order.getTransactionId())
                        .setBeforeM(serviceMember.getBalance())
                        .setMoney(memberProfit)
                        .setFee(companyProfit)
                        .setFeeScale(scale.stripTrailingZeros().toPlainString())
                        .setBalance(serviceBalance)
        );

        //修改订单状态
        int orderRow = dispatchOrderMapper
                .update(null,
                        new LambdaUpdateWrapper<TDispatchOrder>()
                                .set(TDispatchOrder::getStatus, DispatchOrderStatusEnum.finish.getStatus())
                                .set(TDispatchOrder::getVisitCount, redis.hIncrBy(CacheKey.DISPATCH.visitCount, order.getId().toString(), 0))
                                .set(TDispatchOrder::getEndTime, LocalDateTime.now())
                                .eq(TDispatchOrder::getId, order.getId())
                                .eq(TDispatchOrder::getStatus, DispatchOrderStatusEnum.processing.getStatus())

                );
        applyMapper.update(null, new LambdaUpdateWrapper<TDispatchOrderApply>()
                .set(TDispatchOrderApply::getStatus, DispatchOrderStatusEnum.finish.getStatus())
                .eq(TDispatchOrderApply::getOrderId, order.getId())
                .eq(TDispatchOrderApply::getApplyMId, serviceId)
        );

        Check.state(row == 1 && logRow == 1 && orderRow == 1, ExpCode.DB_UPDATE_ERR);
        redis.hDel(CacheKey.DISPATCH.visitCount, order.getId().toString());

        //处理推广
//        Long parentId = serviceMember.getParentId();
//        if (parentId > 0) {
//            Integer serviceCount = memberMapper.selectCount(
//                    new LambdaQueryWrapper<TMember>()
//                            .eq(TMember::getParentId, parentId)
//                            .ge(TMember::getIdStatus, CommonStatus.NORMAL.getType()));
//            scale = spreadSettingMapper.selectList(null)
//                    .stream()
//                    .filter(f -> f.getConditions() <= serviceCount)
//                    .map(TSpreadSetting::getScale)
//                    .max(BigDecimal::compareTo)
//                    .orElse(BigDecimal.ZERO);
//
//            if (scale.compareTo(BigDecimal.ZERO) > 0) {
//                //推广盈利收益比例大于 0 进行推广利润加成
//                TMember spreadMemberInfo = memberMapper
//                        .selectOne(
//                                new LambdaQueryWrapper<TMember>()
//                                        .select(TMember::getAutoId, TMember::getId, TMember::getBalance, TMember::getConsumeMoney, TMember::getOperateMoney,
//                                                TMember::getRechargeMoney, TMember::getIncomeMoney, TMember::getPopularMoney, TMember::getVersion, TMember::getParentId)
//                                        .eq(TMember::getAutoId, parentId)
//                        );
//                if (spreadMemberInfo != null) {
//                    Long spreadVersion = spreadMemberInfo.getVersion();
//                    BigDecimal spreadMoney = spreadMemberInfo.getBalance();
//                    spreadProfit = price.multiply(scale.divide(AppConst.b100, 4));
//                    BigDecimal spreadBalance = spreadMoney.add(spreadProfit);
//                    //推广佣金 分成占比 由公司抽成金额扣减
//                    //推广盈利金额入账
//                    int memberRow =
//                            memberMapper
//                                    .update(null,
//                                            new LambdaUpdateWrapper<TMember>()
//                                                    .set(TMember::getBalance, spreadBalance)
//                                                    .set(TMember::getVersion, spreadVersion + 1)
//                                                    .set(TMember::getIncomeMoney, spreadMemberInfo.getIncomeMoney().add(spreadProfit))
//                                                    .eq(TMember::getId, spreadMemberInfo.getId())
//                                                    .eq(TMember::getVersion, spreadVersion)
//                                    );
//
//                    //金额日志记录
//                    int spreadLogRow = balanceLogMapper.insert(
//                            new TMemberBalanceLog()
//                                    .setStatus(CommonStatus.NORMAL.getType())
//                                    .setMId(spreadMemberInfo.getId())
//                                    .setPayTime(LocalDateTime.now())
//                                    .setTips(BalanceLogEnum.SPREAD_PROFIT.getTips())
//                                    .setTradeType(BalanceLogEnum.SPREAD_PROFIT.getType())
//                                    .setMethod(Integer.parseInt(PaymentEnum.SYSTEM_PAY.getType()))
//                                    .setTradeNo(order.getOrderId().toString())
//                                    .setTransactionId(order.getTransactionId())
//                                    .setBeforeM(spreadMoney)
//                                    .setMoney(spreadProfit)
//                                    .setFee(BigDecimal.ZERO)
//                                    .setFeeScale(scale.divide(AppConst.b100, 3, 4).toString())
//                                    .setBalance(spreadBalance)
//                    );
//                    Check.state(spreadLogRow == 1 && memberRow == 1, ExpCode.DB_UPDATE_ERR);
//
//                }
//            }
//        }


        //  记录订单分账日志
        int splitRow =
                splitMapper
                        .insert(new TOrderSplit()
                                .setC2cOrderId(order.getOrderId())
                                .setCompanyCommission(order.getBeforePrice().add(companyProfit))
                                .setMemberCommission(memberProfit)
                                .setOriginOrderPrice(order.getPrice())
                                .setRealPrice(order.getPrice())
                                .setOrderType(OrderSplitEnum.DISPATCH_ORDER.getType())
                                .setSpreadMoney(BigDecimal.ZERO)
                                .setSpreadScale(BigDecimal.ZERO));
        if (splitRow != 1)
            logger.error("分账信息添加失败 orderId:{},company:{},member:{},payPrice:{},", id, order.getId(), memberProfit, order.getPrice());

        TMember consumeMember = memberService.getMemberMoneyInfo(order.getMId());
        BigDecimal consumeMoney = consumeMember.getConsumeMoney().add(order.getPrice());
        Long versionC = consumeMember.getVersion();
        row =
                memberMapper
                        .update(null,
                                new LambdaUpdateWrapper<TMember>()
                                        .set(TMember::getConsumeMoney, consumeMoney)
                                        .set(TMember::getVersion, versionC + 1)
                                        .eq(TMember::getId, mId)
                                        .eq(TMember::getVersion, versionC)
                        );
        if (row != 1)
            logger.error("总消费数据修改失败 mId:{},orderId:{},payPrice:{}", mId, id, order.getPrice());


        return true;
    }

    @Override
    public PageResult<ServiceDispatchOrderDTO> serviceDispatchOrderList(String mId, Integer type, int pageNo, int pageSize) {
        type = type == -1 ? null : type;
        Page<ServiceDispatchOrderDTO> res = applyMapper.selectApplyOrderInfo(new Page(pageNo, pageSize), mId, type);
        res.getRecords().forEach(
                item ->
                        item
                                .setMemberImg(StringUtils.isBlank(item.getMemberImg()) ? "" : ossConfig.getHostname() + "/" + item.getMemberImg())
                                .setImages(strToList(",", item.getImgs()).stream().filter(StringUtils::isNotBlank).map(url -> ossConfig.getHostname() + "/" + url).collect(Collectors.toList()))
        );
        return new PageResult<ServiceDispatchOrderDTO>()
                .setCurrent(res.getCurrent())
                .setRecords(res.getRecords())
                .setSize(res.getSize())
                .setTotal(res.getTotal())
                .setPages(res.getPages());
    }

    @Override
    public Boolean existsDispatchOrder(String id) {
        Integer dispatchCount = dispatchOrderMapper
                .selectCount(new QueryWrapper<>(new TDispatchOrder()
                        .setMId(Parse.toLong(id))));
        if (dispatchCount > 0)
            return true;
        else
            return applyMapper.selectCount(new QueryWrapper<>(new TDispatchOrderApply().setApplyMId(Parse.toLong(id)))) > 0;

    }

    @Override
    public boolean publishOrder(String mId, DispatchOrderParams params) {
        TProductCategory category = categoryService.getProductCategoryById(params.getCategoryId());
        Check.notNull(category, ExpCode.DATA_SELECT_NULL);


        TDispatchOrder order = new TDispatchOrder()
                .setCategory(category.getCaption())
                .setCategoryId(category.getId())
                .setContent(params.getContent())
                //   .setTimeLimit(listToStr(params.getTimeLimit()))
                .setImgs(params.getImgs())
                .setPrice(new BigDecimal(params.getPrice()))
                .setCityCode(params.getCityCode())
                .setCityName(params.getCityName())
                .setMId(Parse.toLong(mId))
                .setStatus(-1)
                .setUnit(params.getUnit());


        return dispatchOrderMapper.insert(order) == 1;
    }

    @Override
    public ConsumeOrderDetailInfoDTO getApplyOrderInfo(String id) {
        ConsumeOrderDetailInfoDTO ret = new ConsumeOrderDetailInfoDTO();
        //派单信息
        TDispatchOrder dispatchOrder = dispatchOrderMapper.selectById(id);
        Check.notNull(dispatchOrder, ExpCode.ORDER_NOT_EXIST);


        TMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<TMember>()
                        .select(TMember::getNickName, TMember::getImgUrl, TMember::getArea, TMember::getId)
                        .eq(TMember::getId, dispatchOrder.getMId())
        );

        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);

        return ret
                .setDispatchOrderId(dispatchOrder.getId().toString())
                .setContent(dispatchOrder.getContent())
                .setPrice(dispatchOrder.getPrice().stripTrailingZeros().toPlainString())
                .setBeginDate(dispatchOrder.getBeginTime().toLocalDate())
                .setBeginTime(dispatchOrder.getBeginTime().toLocalTime())
                .setOrderId(dispatchOrder.getOrderId().toString())
                .setOrderTime(dispatchOrder.getAddTime())
                .setMId(member.getId().toString())
                .setNickname(member.getNickName())
                .setStatus(dispatchOrder.getStatus())
                .setDuration(dispatchOrder.getOrderTime())
                .setMemberImg(StringUtils.isBlank(member.getImgUrl()) ? "" : ossConfig.getHostname() + "/" + member.getImgUrl())
                .setArea(dispatchOrder.getCityName())
                .setCancel(true)
                .setFinished(false);
    }

    @Override
    public boolean cancelApplyOrder(String mId, String id) {
        return applyMapper.update(
                null,
                new LambdaUpdateWrapper<TDispatchOrderApply>()
                        .set(TDispatchOrderApply::getStatus, DispatchOrderStatusEnum.cancel.getStatus())
                        .eq(TDispatchOrderApply::getApplyMId, mId)
                        .eq(TDispatchOrderApply::getOrderId, id)) == 1;

    }

    @Override
    public Boolean existsApplyOrder(Long id) {
        return applyMapper.selectCount(new QueryWrapper<>(new TDispatchOrderApply().setApplyMId(id))) > 0;
    }

    @Override
    public Boolean existsDispatchOrders(Long id) {
        return dispatchOrderMapper.selectCount(new QueryWrapper<>(new TDispatchOrder().setMId(id))) > 0;
    }

    @Override
    public boolean checkDispatchOrder(String mId) {
        LocalDateTime time = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        Integer dispatchCount = dispatchOrderMapper
                .selectCount(
                        new LambdaQueryWrapper<TDispatchOrder>()
                                .eq(TDispatchOrder::getMId, mId)
                                .eq(TDispatchOrder::getBeforeStatus, PayStatusEnum.FINISH.getType())
                                .ge(TDispatchOrder::getAddTime, time)
                );
        return dispatchCount == 0;
    }
}
